﻿namespace Webinator.ExtensionMethods
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text.RegularExpressions;
    using Enums;

    /// <summary>
    /// Useful extension methods.
    /// </summary>
    public static class StringExtensions
    {
        /// <summary>
        /// Removes the specified substring from the string provided.
        /// </summary>
        /// <param name="value">The string to manipulate.</param>
        /// <param name="remove">The substring to remove.</param>
        /// <returns>A new string with the specified substring removed and trimmed.</returns>
        public static string RemoveAndTrim(this string value, string remove)
        {
            if (!string.IsNullOrWhiteSpace(value) || !string.IsNullOrEmpty(remove))
            {
// ReSharper disable PossibleNullReferenceException
                value = value.Replace(remove, string.Empty).Trim();
// ReSharper restore PossibleNullReferenceException
            }

            return value;
        }

        /// <summary>
        /// Removes any non alpha-numeric characters.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>
        /// A string with any non alpha-numeric characters removed.
        /// </returns>
        public static string AlphaNumericOnly(this string value)
        {
            if (!string.IsNullOrWhiteSpace(value))
            {
                value = Regex.Replace(value, "[^a-zA-Z0-9]*", string.Empty);
            }

            return value;
        }

        /// <summary>
        /// Removes leading and trailing spaces from the specified string and replaces all sequences of white space characters with one white space character and returns the result.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>
        /// The modified string.
        /// </returns>
        public static string NormalizeSpace(this string value)
        {
            if (!string.IsNullOrWhiteSpace(value))
            {
                value = Regex.Replace(value, "[ ]{2,}", " ");
                return value.Trim();
            }

            return value;
        }

        /// <summary>
        /// Removes all carriage returns and line feeds.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>
        /// The modified string.
        /// </returns>
        public static string RemoveNewLines(this string value)
        {
            if (!string.IsNullOrWhiteSpace(value))
            {
                value = value.Replace("\r", string.Empty).Replace("\n", string.Empty);
            }

            return value;
        }

        /// <summary>
        /// Replaces the first occurrence of the specified string with the specified replacement string.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <param name="oldValue">The old value.</param>
        /// <param name="newValue">The new value.</param>
        /// <returns>
        /// The modified string.
        /// </returns>
        public static string ReplaceFirstOccurrence(this string value, string oldValue, string newValue)
        {
            if (string.IsNullOrEmpty(value))
            {
                return string.Empty;
            }

            if (string.IsNullOrEmpty(oldValue))
            {
                return value;
            }

            if (string.IsNullOrEmpty(newValue))
            {
                newValue = string.Empty;
            }

            int index = value.IndexOf(oldValue, StringComparison.Ordinal);

            if (index == -1)
            {
                return value;
            }

            return value.Remove(index, oldValue.Length).Insert(index, newValue);
        }

        /// <summary>
        /// Gets the filename from the absolute or relative path passed.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>
        /// The filename.
        /// </returns>
        public static string FilenameFromPath(this string value)
        {
            if (!string.IsNullOrWhiteSpace(value))
            {
                value = Regex.Replace(value, @".*\\(.*)", "$1");
            }

            return value;
        }

        /// <summary>
        /// Returns the absolute path of the provided relative path.
        /// If the path is already absolute, it returns the path without modification.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>
        /// The absolute path.
        /// </returns>
        public static string AbsolutePath(this string value)
        {
            string absolutePath = value;
            if (Regex.IsMatch(value, @"^\\\\?.*|^[a-zA-Z](?!:).*"))
            {
                absolutePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, value);
            }

            return absolutePath;
        }

        /// <summary>
        /// Trims the leading and trailing double quotes from the string.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns>
        /// The modified string.
        /// </returns>
        public static string TrimLeadingAndTrailingDoubleQuotes(this string value)
        {
            // Remove starting "
            if (value.StartsWith(@""""))
            {
                value = value.Remove(0, 1);
            }

            // Remove ending "
            if (value.EndsWith(@""""))
            {
                value = value.Remove(value.Length - 1, 1);
            }

            return value;
        }

        /// <summary>
        /// Verifies whether the string array is sorted or not.
        /// </summary>
        /// <param name="values">The string array.</param>
        /// <param name="sorted">The sort type.</param>
        /// <returns>
        /// A boolean value indicating whether the string array is sorted according to the <c>Sort</c> value.
        /// </returns>
        public static bool IsSorted(this IEnumerable<string> values, Sorted sorted)
        {
            bool isSorted = true;

            var list = values.ToList();
            for (int i = 0; i < list.Count - 2; i++)
            {
                switch (sorted)
                {
                    case Sorted.Ascending:
                        if (string.CompareOrdinal(list[i], list[i + 1]) > 0) isSorted = false;

                        break;
                    case Sorted.Descending:
                        if (string.CompareOrdinal(list[i], list[i + 1]) < 0) isSorted = false;

                        break;
                }
            }

            return isSorted;
        }

        /// <summary>
        /// Performs the given comparison on the value passed. Include the <c>oldValue</c> to look for any change.
        /// </summary>
        /// <param name="value">The new value.</param>
        /// <param name="comparison">Indicates how to match the <c>value</c>.</param>
        /// <param name="oldValue">The old value - required if searching for any change.</param>
        /// <param name="match">The text to look for, if set to null then it looks for any change.</param>
        /// <returns>
        /// A boolean value indicating whether a successful match was made.
        /// </returns>
        public static bool StringMatch(this string value, Comparison comparison, string oldValue, string match)
        {
            bool conditionMet = false;

            if (string.IsNullOrEmpty(match) && !string.IsNullOrEmpty(value))
            {
                // Any change
                if (oldValue != value)
                {
                    conditionMet = true;
                }
            }
            else
            {
                switch (comparison)
                {
                    case Comparison.IsExact:
                        if (value == match)
                        {
                            conditionMet = true;
                        }

                        break;
                    case Comparison.DoesNotMatch:
                        if (value != match)
                        {
                            conditionMet = true;
                        }

                        break;
                    case Comparison.StartsWith:
                        if (value.StartsWith(match))
                        {
                            conditionMet = true;
                        }

                        break;
                    case Comparison.DoesNotStartWith:
                        if (!value.StartsWith(match))
                        {
                            conditionMet = true;
                        }

                        break;
                    case Comparison.EndsWith:
                        if (value.EndsWith(match))
                        {
                            conditionMet = true;
                        }

                        break;
                    case Comparison.DoesNotEndWith:
                        if (!value.EndsWith(match))
                        {
                            conditionMet = true;
                        }

                        break;
                    case Comparison.Contains:
                        if (value.Contains(match))
                        {
                            conditionMet = true;
                        }

                        break;
                    case Comparison.DoesNotContain:
                        if (!value.Contains(match))
                        {
                            conditionMet = true;
                        }

                        break;
                    case Comparison.RegexMatch:
                        if (Regex.IsMatch(value, match))
                        {
                            conditionMet = true;
                        }

                        break;
                    case Comparison.NotRegexMatch:
                        if (!Regex.IsMatch(value, match))
                        {
                            conditionMet = true;
                        }

                        break;
                }
            }

            return conditionMet;
        }

        /// <summary>
        /// Performs the given comparison on the value passed.  Include the <c>oldValue</c> to look for any change.
        /// </summary>
        /// <param name="value">The new value.</param>
        /// <param name="comparison">Indicates how to match the <c>value</c>.</param>
        /// <param name="match">The text to look for.</param>
        /// <returns>
        /// A boolean value indicating whether a successful match was made.
        /// </returns>
        public static bool StringMatch(this string value, Comparison comparison, string match)
        {
            return StringMatch(value, comparison, null, match);
        }
    }
}
